import datetime as dtm
import logging
import operator
import urllib

# from operator import itemgetter

import config as c
import parsers as p
import request as r
import tools as t

def sort_table(table, cols):
    """ sort a table by multiple columns
        table: a list of lists (or tuple of tuples) where each inner list
               represents a row
        cols:  a list (or tuple) specifying the column numbers to sort by
               e.g. (1,0) would sort by column 1, then by column 0
    """
    for col in reversed(cols):
        table = sorted(table, key=operator.itemgetter(col))
    return table

def conflict_report():
    # Initialize various items.
    log = logging.getLogger('TiVoToDo.reports.conflict_report')
    last_chan = None
    last_row = None
    last_tivo = None
    rdl_set = set()
    spm_set = set()
    
    # Loop through the sorted raw data list.
    for row in sort_table(c.rdl, (12, 10, 11)):

        # Select rows that have unique titles, TiVo names, or channels.
        if ((row[12] == last_row and row[10] != last_tivo) or 
            (row[12] == last_row and row[11] != last_chan) or 
             row[12] != last_row) and row[13] == 'Season Pass':
            rdl_set.add((row[10], row[11], row[12], row[15]))
        
        # Identify the data break values.
        last_chan = row[11]
        last_row = row[12]
        last_tivo = row[10]

    # Loop through the sorted raw data list.
    for row in c.spm:
        spm_set.add((row[4], row[2][:-6], row[1], row[5]))
    for row in rdl_set:
        log.debug('rdl: %s' % str(row))
    for row in spm_set:
        log.debug('spm: %s' % str(row))
    parser  = p.SearchParser()
    for row in spm_set.difference(rdl_set):
        log.info('dff: %s' % str(row))
    for row in spm_set.difference(rdl_set):
        log.info('\n%s: %s' % (row[0], row[2]))
        c.spm_titl = row[2]
        # First run only
        log.info('New show:')
        url = c.base_url + c.srch_url + 'tsn=' + row[3] + \
             '&searchTitle=' + urllib.quote(row[2]) + \
             '&repeat=false'
        login_data = None
        r.request_url(url, parser, login_data)
        
        # Repeats
        log.info('Repeat:')
        url = c.base_url + c.srch_url + 'tsn=' + row[3] + \
             '&searchTitle=' + urllib.quote(row[2])
        login_data = None
        r.request_url(url, parser, login_data)
        
def date_report(key, order, file, report):
    log = logging.getLogger('TiVoToDo.reports.date_report')
    last_row = None

    # Test to see if a display is wanted.
    if report in c.display_list or 'All' in c.display_list:
        # Print a header row.
        log.info('\nDate  Day %s %s %s %s %s Duration\n' % (
                 'Time'.center(8), 'Tivo'.center(16),
                 'Channel'.center(14), 'Type'.center(11),
                 'Title'.center(40)))

        # Loop through the sorted raw data list.
        for row in sort_table(c.rdl, order):

            # Identify only a show's actual start time.
            if row[4] == 0:

                # Test for data break based on report type.
                if row[key] != last_row and last_row != None:
                    x = raw_input("\nViewing sorted by " +
                                  "%s. Press Enter to continue\n" % report)
                # Print column justified data.
                log.info('%s %s %s %s %s %s %s %s' % (row[0], row[1], row[2],
                         row[10].center(16), row[11].center(14),
                         row[13].center(11), row[12].center(40),
                         str(row[3]).center(8)))
                # Identify the data break value.
                last_row = row[key]

        x = raw_input("\nViewing sorted by " +
                      "%s. Press Enter to continue\n" % report)
    # Test to see if a file is wanted.
    if report in c.csv_list or 'All' in c.csv_list:
        # Initialize an empty list.
        tdl_csv = []

        # Loop through the sorted raw data list.
        for row in sort_table(c.rdl, order):

            # Identify only a show's actual start time.
            if row[4] == 0:

                # Test for data break based on report type.
                if row[key] != last_row:
                    tdl_csv.append((''),)
                # Add the data to the list.
                tdl_csv.append((row[0], row[1], row[2], row[10],
                                row[11], row[13], row[12], row[3]))
                # Identify the data break value.
                last_row = row[key]

        # Insert a header row.
        tdl_csv[0] = ['Date', 'Day', 'Time', 'Tivo',
                      'Channel', 'Type', 'Title', 'Duration']
        # Write the file.
        t.make_csv(tdl_csv, file)

def show_report():
    # Initialize various items.
    log = logging.getLogger('TiVoToDo.reports.show_report')
    last_chan = None
    last_row = None
    last_tivo = None
    max_len = 0
    tdl_csv = []

    # Test to see if display is wanted.
    if 'Show' in c.display_list or 'All' in c.display_list:
        # Print a header row.
        log.info('%s %s %s %s %s\n' % ('Title'.center(40), 'Tivo'.center(16),
                 'Duration', 'Type'.center(12), 'Channel'.center(14)))

        # Loop through the sorted raw data list.
        for row in sort_table(c.rdl, (12, 10, 11)):

            # Select rows that have unique titles, TiVo names, or channels.
            if (row[12] == last_row and row[10] != last_tivo) or \
               (row[12] == last_row and row[11] != last_chan) or \
                row[12] != last_row:
                    # Print column justified data.
                    log.info('%s %s %s %s %s' % (row[12].center(40),
                             row[10].center(16), str(row[3]).center(8),
                             row[13].center(12), row[11].center(14)))
            # Identify the data break values.
            last_chan = row[11]
            last_row = row[12]
            last_tivo = row[10]
        x = raw_input("\nViewing Shows. Press Enter to continue\n")

    # Test to see if a file is wanted.
    if 'Show' in c.csv_list or 'All' in c.csv_list:

        # Loop through the sorted raw data list.
        for row in sort_table(c.rdl, (12, 10, 11)):

            # Select rows that have unique titles, TiVo names, or channels.
            if (row[12] == last_row and row[10] != last_tivo) or \
               (row[12] == last_row and row[11] != last_chan) or \
                row[12] != last_row:
                    # Create a row of information.
                    tdl_row = [row[12], row[10], row[3], row[13], row[11]]
                    # Identify the shows dictionary key.
                    i = c.shows[row[14]]
                    # Identify the containing list of channels.
                    j = i[8][0]

                    # Update the max number of columns to add.
                    if len(j) > max_len:
                        max_len = len(j)

                    # Loop through list of other channels.
                    for k in range(len(j)):

                        # Don't include the channel the show is recording on.
                        if row[11] not in j[k][1].strip():
                            # Add to row.
                            tdl_row.append(j[k][1].strip())

                    # Add to list.
                    tdl_csv.append((tdl_row))

            # Identify the data break values.
            last_chan = row[11]
            last_row = row[12]
            last_tivo = row[10]

        # Create a header row.
        tdl_row =  ['Title', 'Tivo', 'Duration', 'Type', 'Recording Channel']

        # Loop through the max number or columns.
        for i in range(max_len - 1):

            # Add to the header row.
            tdl_row.append('Alternate Channel')

        # Insert the header row.
        tdl_csv[0] = tdl_row
        # Write the file.
        t.make_csv(tdl_csv, 'ToDo.By.Show.csv')

def tuner_report():
    log = logging.getLogger('TiVoToDo.reports.tuners_report')

    # Sort the raw data list by date, TiVo name, then show title.
    rdl = sort_table(c.rdl, (5, 10, 12))

    # Set time adjustment based on clipping.
    offset = dtm.timedelta(minutes=int(c.offset[1]))
    thirty = dtm.timedelta(minutes=30)

    # Initialize a 'free tuners' list.
    for tivo in c.tivos.iterkeys():
        c.tuners[tivo] = [c.free_tuner, 0, 0, 0, c.free_tuner,
                          c.free_tuner, 0, 0, 0, c.free_tuner]

    # Establish the starting point.
    a = 0

    # Create an initial time table based on first record's date.
    tt = t.time_table(rdl[a][8].year,
                      rdl[a][8].month,
                      rdl[a][8].day)

    # Find a tuner, but don't commit the record to the time slot dictionary.
    def process_record(rec,
                       start_prev,
                       start_next,
                       show_start):
        t.tivo_tuners(rdl[rec][10],
                      rdl[rec][3],
                      rdl[rec][7],
                      rdl[rec][12],
                      start_prev,
                      start_next,
                      show_start)

    # Find a tuner and commit the record to the time slot dictionary.
    def commit_record(rec,
                      time,
                      start_prev,
                      start_next,
                      show_start):
        time_slot[time].extend(t.tivo_tuners(rdl[rec][10],
                                             rdl[rec][3],
                                             rdl[rec][7],
                                             rdl[rec][12],
                                             start_prev,
                                             start_next,
                                             show_start))

    # Start a conditional loop, ending with the last rdl record.
    while a < len(rdl):

        # Initilize a list containing one day's time in 30 minute increments.
        time_slot = []
        for b in range(len(tt)):
            time_slot.append([t.date2str(tt[b])[2]])

        # Start a conditional loop, ending with a date change.
        while rdl[a][8] >= tt[0] and \
              rdl[a][8] <= tt[len(tt) - 1] + \
              dtm.timedelta(minutes=29) + \
              offset:

            # Create a display date variable.
            d_date = rdl[a]

            # Set boolean value for this record's start time
            # compared to previous record's start time.
            show_start = rdl[a][4] == 0
            start_prev = t.check_time(rdl[a][8]) == t.check_time(rdl[a-1][8])
            log.debug(' / '.join([str(rdl[a][8]),
                                  str(rdl[a-1][8]),
                                  str(start_prev)]))
            if a == len(rdl) - 1:
                start_next = False
            else:
                # Set boolean value for this record's start time
                # compared to next record's end time.
                start_next = t.check_time(rdl[a][8]) == t.check_time(rdl[a+1][8])
                log.debug(' / '.join([str(rdl[a][8]),
                                      str(rdl[a+1][8]),
                                      str(start_next)]))

            # Debug this record's information.
            counter = 0
            for item in rdl[a]:
                log.debug('%s[%s] - %s' % (a, counter, item))
                counter += 1
            log.debug('%s %s thru %s' % (rdl[a][8],
                                         tt[0],
                                         tt[len(tt) -1] + thirty + offset))
            log.debug('%d, start_prev = %s, start_next = %s' % (a,
                                                                start_prev,
                                                                start_next))

            # Loop through the time table for the date.
            for b in range(len(tt)):

                # Last time slot for this date
                if b == len(tt) - 1 and rdl[a][8] >= tt[b]:
                    log.debug('A')

                    # More shows follow that air at this time.
                    if start_next:
                        log.debug('AA')
                        process_record(a,
                                       start_prev,
                                       start_next,
                                       show_start)
                    # Last show that airs at this time.
                    else:
                        log.debug('AB')
                        commit_record(a,
                                      b,
                                      start_prev,
                                      start_next,
                                      show_start)

                # All other time slots.
                elif rdl[a][8] >= tt[b] and rdl[a][8] < tt[b] + thirty:
                    log.debug('B')

                    # More shows follow that air at this time.
                    if start_next:
                        log.debug('BA')
                        process_record(a,
                                       start_prev,
                                       start_next,
                                       show_start)
                    # Last show that airs at this time.
                    else:
                        log.debug('BB')
                        commit_record(a,
                                      b,
                                      start_prev,
                                      start_next,
                                      show_start)

            # Get the next record
            a += 1

            # Last record surpassed, get out of this loop.
            if a > len(rdl) - 1:
                break

        # Print the output to the console.
        if 'Tuner' in c.display_list or 'All' in c.display_list:

            # Log the show's date.
            log.info('\n%s %s' % (d_date[0], d_date[1]))
            hdr_row1 = hdr_row2 = ' ' * 9

            # Create the header rows.
            for k in c.tivos.iterkeys():
                hdr_row1 += '[' + k.center(35, ' ') + '] '
                hdr_row2 += '[    Tuner  1    ] ' \
                            '[    Tuner  2    ] '

            # Log the header rows.
            log.info(hdr_row1)
            log.info(hdr_row2)

            # Loop through the list of found TiVos.
            for i in range(len(time_slot)):

                # Identify the number of items in this row.
                j = len(time_slot[i]) - 1

                # Loop through the number of all tuners, +1 for time.
                for k in range((len(c.tivos) * 2) + 1):

                    # Identify the first item in the row: time.
                    if k == 0:

                        # Create the time portion of the data row.
                        data_row = time_slot[i][k].rjust(8, ' ')

                    # An item other than time was found.
                    elif k <= j:

                        # Get the item.
                        display = time_slot[i][k].strip()

                        # Test if the item is a free tuner.
                        if len(display) == 0 or not display:
                            data_row += ' |' + ' ' * 16 + '|'

                        # The item is short title.
                        elif len(display) < 16:
                            data_row += ' |' + display.center(16, ' ') + '|'

                        # The item is a long title.
                        else:
                            data_row += ' |' + display[:12] + '... |'

                    # Pad the remaining tuners.
                    else:
                        data_row += ' |' + ' ' * 16 + '|'

                # Log the data row.
                log.info(data_row)

            x = raw_input("\nViewing tuner activity. " +
                          "Press Enter to continue\n")

        # Write the data to the file.
        if 'Tuner' in c.csv_list or 'All' in c.csv_list:

            # Create header row.
            day = ' '.join([d_date[0], d_date[1]])
            time_slot.insert(0, [day])

            for k in c.tivos.iterkeys():
                time_slot[0].extend([k + ' - Tuner 1'])
                time_slot[0].extend([k + ' - Tuner 2'])

            # Establish a filename based on date.
            fname = '.'.join(('Tuner.Activity',
                              d_date[0].replace('/', '-'),
                              d_date[1], 'csv'))

            # Write the file.
            t.make_csv(time_slot, fname)

        # Last record surpassed, get out of this loop, too.
        if a > len(rdl) - 1:
            break

        # Create a time table based on new record's date.
        tt = t.time_table(rdl[a][8].year,
                          rdl[a][8].month,
                          rdl[a][8].day)
